package bean.managed;

import entity.PurchaseOrderEntity;
import bean.managed.util.JsfUtil;
import bean.session.PurchaseOrderEntityFacade;

import entity.AddressEntity;
import entity.CompletedGoodsEntity;
import entity.ContactEntity;
import entity.CustomerEntity;
import entity.PriceListEntity;
import entity.ProductQuantityPriceEntity;
import entity.RoleEntity;
import entity.SalesLeadEntity;
import entity.SalesQuotationEntity;
import entity.ShippingRequestEntity;
import entity.SystemUserEntity;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.SelectItem;
import managedbean.AbstractBacking;
import org.primefaces.event.SelectEvent;
import type.CustomerType;
import type.PaymentMethod;
import util.Mailer;

@ManagedBean(name = "purchaseOrderEntityController")
@SessionScoped
public class PurchaseOrderEntityController extends AbstractBacking implements Serializable {

    private PurchaseOrderEntity current;
    private DataModel items = null;
    private DataModel searchItems = null;
    @EJB
    private bean.session.PurchaseOrderEntityFacade ejbFacade;
    @EJB
    private bean.session.ShippingRequestEntityFacade shippingRequestFacade;
    private String attribute = "id";
    private String input;
    private ProductQuantityPriceEntity currentPQP;
    private ProductQuantityPriceEntity currentPQP2;
    private ProductQuantityPriceEntity currentPQP3;
    private ProductQuantityPriceEntity currentPQP4;
    private SalesLeadEntityController salesLeadEntityController;
    private CustomerEntityController customerEntityController;
    private SalesQuotationEntityController salesQuotationEntityController;
    private SalesQuotationEntity selectedItem;
    private SystemUserEntity salesExecutive;
    @ManagedProperty(value = "#{salesOrderEntityController}")
    private SalesOrderEntityController salesOrderEntityController;
    @ManagedProperty(value = "#{systemMessageController}")
    private SystemMessageController systemMessageController;
    @ManagedProperty(value = "#{contactEntityController}")
    private ContactEntityController contactEntityController;
    private String note;
    private List<AddressEntity> shippingAddresses;

    public PurchaseOrderEntityController() {
    }

    public boolean checkSystemUser() {
        if (getCurrentUser() instanceof SystemUserEntity) {
            return true;
        }
        return false;
    }

    public boolean checkSalesLead() {
        if (getLoginSalesLead() instanceof SalesLeadEntity) {
            return true;
        }
        return false;
    }

    public boolean checkCustomer() {
        if (getLoginCustomer() instanceof CustomerEntity) {
            return true;
        }
        return false;
    }

    public PurchaseOrderEntity getSelected() {
        if (current == null) {
            current = new PurchaseOrderEntity();
        }
        return current;
    }

    public void setSelected(PurchaseOrderEntity purchaseOrder) {
        this.current = purchaseOrder;
    }

    private PurchaseOrderEntityFacade getFacade() {
        return ejbFacade;
    }

    public String prepareList() {
        recreateModel();
        return "/entities/purchaseOrderEntity/List?faces-redirect=true";
    }

    public void resetContactAndAddresses() {
        ContactEntity contact = null;
        if (current.getCustomer() != null) {
            contact = current.getCustomer().getContact();
        } else if (current.getSalesLead() != null) {
            contact = current.getSalesLead().getContact();
        } else {
            contact = new ContactEntity();
        }
        contactEntityController.setupCurrent(contact);
    }

    public String prepareView() {
        current = (PurchaseOrderEntity) getItems().getRowData();
        resetContactAndAddresses();

        shippingAddresses = new ArrayList<AddressEntity>();
        for (ShippingRequestEntity request : current.getShippingRequests()) {
            shippingAddresses.add(request.getAddress());
        }
        return "/entities/purchaseOrderEntity/View?faces-redirect=true";
    }

    public String prepareCreate() {
        current = new PurchaseOrderEntity();
        resetContactAndAddresses();
        return "/entities/purchaseOrderEntity/Create?faces-redirect=true";
    }

    public String prepareSearch() {
        setSearchItems(getSearchItems());
        return "SearchList";
    }

    public DataModel getSearchItems() {
        if (getAttribute().equals("id")) {
            searchItems = ejbFacade.searchPurchaseOrderById(getAttribute(), getInput());
        } else if (getAttribute().equals("Name")) {
            searchItems = ejbFacade.searchPurchaseOrderByName(getAttribute(), getInput());
        }
        items = searchItems;
        return searchItems;
    }
    
    private String verifyShippingRequestTotal(){
        String result = "";
        
        ArrayList<CompletedGoodsEntity> mismatches = current.getMismatchedPqpAndShippingRequest();
        for(CompletedGoodsEntity goods : mismatches){
            result += goods.getProductName() + ", ";
        }
        if(!result.isEmpty()){
            result = result.substring(0,result.length()-2) + " requested shipping quantity does not match total purchased amount";
        }
        
        return result;
    }

    public String create() {
        try {           
            checkPricePerUnit(currentPQP);
            checkPricePerUnit(currentPQP2);
            checkPricePerUnit(currentPQP3);
            checkPricePerUnit(currentPQP4);

            getCurrentPQP().setProduct(getFacade().getPurchaseOrderProduct("Classic Nutri Bar (Nuts)"));
            current.addPqp(currentPQP);
            
            getCurrentPQP2().setProduct(getFacade().getPurchaseOrderProduct("Classic Nutri Bar (Fruits)"));
            current.addPqp(currentPQP2);
            
            getCurrentPQP3().setProduct(getFacade().getPurchaseOrderProduct("Premium Power Bar (Chocolate Nuts)"));
            current.addPqp(currentPQP3);
            
            getCurrentPQP4().setProduct(getFacade().getPurchaseOrderProduct("Premium Power Bar (Redcurrant Fruits)"));
            current.addPqp(currentPQP4);

            if (checkSystemUser()) {
                current.setSystemUser(getCurrentUser());
            } else if (checkSalesLead()) {
                current.setSalesLead(getLoginSalesLead());
            } else if (checkCustomer()) {
                current.setCustomer(getLoginCustomer());
            }
            
            //verify that shipping requests match pqp
            String verificationResult = verifyShippingRequestTotal();
            if(!verificationResult.isEmpty()){
                JsfUtil.addErrorMessage(verificationResult);
                return null;
            }
            
            current.created(getLoginPerson());
            getCurrentPQP().created(getLoginPerson());
            getCurrentPQP2().created(getLoginPerson());
            getCurrentPQP3().created(getLoginPerson());
            getCurrentPQP4().created(getLoginPerson());

//            for(ShippingRequestEntity request : current.getShippingRequests()){
//                request.setPurchaseOrder(current);               
//                shippingRequestFacade.edit(request);
//            }

            if (current.getSalesLead() != null) {
                getSalesLeadEntityController().setCurrent(current.getSalesLead());
                current.setCustomer(getCustomerEntityController().purchaseOrderConvert());
            }
            if (current.getCustomer() != null) {
                current.getCustomer().getPurchaseOrder().add(current);
                getCustomerEntityController().setCurrent(current.getCustomer());
            }

            //customer did not indicate preferred lead time, preferred lead time = sales quotation indicative lead time
            if (current.getPreferredLeadTime() == null) {
                current.setPreferredLeadTime(current.getSalesQuotation().getIndicativeLeadTime());
            }
            
            setShippingRequestDate();
            getFacade().edit(current);

            systemMessageController.getEjbFacade().createAndSendSystemMessage(current.getCustomer().getCustomerExecutive(),
                    current.getCustomer().getFirstName() + " " + current.getCustomer().getLastName() + " has created Purchase Order # " + current.getId() + ".",
                    "/index", systemMessageController);

            current = null;
            setCurrentPQP(null);
            setCurrentPQP2(null);
            setCurrentPQP3(null);
            setCurrentPQP4(null);
            setSalesExecutive(null);
            recreateModel();
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("PurchaseOrderEntityCreated"));
            return prepareCreate();
        } catch (Exception e) {
            e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }
    
    public void setShippingRequestDate() {
        ArrayList<ShippingRequestEntity> request = new ArrayList<ShippingRequestEntity>(current.getShippingRequests());
        for (int i = 0; i < request.size(); i++) {
            request.get(i).setShippingDate(current.getPreferredLeadTime());
        }
    }
    
    public void calculateQuantity(long quantity, ProductQuantityPriceEntity pqp) {
        pqp.setQuantity(quantity);
        calculatePriceBaseOnPricePerUnit(pqp);
    }

    public void calculatePQP() {
        calculatePriceBaseOnPricePerUnit(currentPQP);
    }

    public void calculatePQP2() {
        calculatePriceBaseOnPricePerUnit(currentPQP2);
    }

    public void calculatePQP3() {
        calculatePriceBaseOnPricePerUnit(currentPQP3);
    }

    public void calculatePQP4() {
        calculatePriceBaseOnPricePerUnit(currentPQP4);
    }

    public void calculatePriceBaseOnPricePerUnit(ProductQuantityPriceEntity pqp) {
        long quantity = pqp.getQuantity();
        double pricePerUnit = pqp.getPricePerUnit();
        if (pricePerUnit == 0) {
            //pqp.setPricePerUnit(getPrice(pqp,current).get(0));
            pqp.setPrice(getPrice(pqp, current).get(1));
        } else {
            pqp.setPrice(pricePerUnit * quantity);
        }
    }

    private void checkPricePerUnit(ProductQuantityPriceEntity pqp) {
        double price = pqp.getPrice();
        long quantity = pqp.getQuantity();
        pqp.setPricePerUnit(price / quantity);
    }

    public ArrayList<Double> getPrice(ProductQuantityPriceEntity pqp, PurchaseOrderEntity purchaseOrder) {
        System.out.println("gettingprice");
        PriceListEntity priceList;

        if (purchaseOrder.getSalesLead() != null) {
            if (purchaseOrder.getSalesLead().getCustomerType().toString().equals(CustomerType.Wholesales)) {
                priceList = getTypePriceList(CustomerType.Wholesales, pqp.getQuantity());
            } else {
                priceList = getTypePriceList(CustomerType.Directsales, pqp.getQuantity());
            }
        } else {
            if (purchaseOrder.getCustomer().getCustomerType().toString().equals(CustomerType.Wholesales)) {
                priceList = getTypePriceList(CustomerType.Wholesales, pqp.getQuantity());
            } else {
                priceList = getTypePriceList(CustomerType.Directsales, pqp.getQuantity());
            }
        }
        return calculatePrice(pqp, priceList);
    }

    public PriceListEntity getTypePriceList(CustomerType type, long quantity) {
        System.out.println("gettingtype");
        PriceListEntity typePriceList = new PriceListEntity();
        ArrayList<PriceListEntity> priceList = getFacade().getPriceList();

        for (int i = 0; i < priceList.size(); i++) {
            if (priceList.get(i).getType().equals(type) && quantity >= priceList.get(i).getTieredQuantity()) {
                typePriceList = priceList.get(i);
            }
        }
        return typePriceList;
    }

    public ArrayList<Double> calculatePrice(ProductQuantityPriceEntity pqp, PriceListEntity priceList) {
        System.out.println("calculating price");
        ArrayList price = new ArrayList<Double>();
        price.add(priceList.getPrice());
        price.add(pqp.getQuantity() * priceList.getPrice());
        return price;
    }

    public String prepareEdit() {
        current = (PurchaseOrderEntity) getItems().getRowData();
        resetContactAndAddresses();
        return "Edit";
    }
    
    public String prepareEditFromView() {
        ArrayList<ProductQuantityPriceEntity> pqp = new ArrayList<ProductQuantityPriceEntity>(current.getProductQuantityPrice());
        for (int i = 0; i < pqp.size(); i++) {
            if (i == 0) {
                currentPQP = pqp.get(i);
            }
            if (i == 1)
                currentPQP2 = pqp.get(i);
            if (i == 2)
                currentPQP3 = pqp.get(i);
            if (i == 3)
                currentPQP4 = pqp.get(i);
        }
        return "Edit";
    }
    
    public String updateEdit() {
       ArrayList<ProductQuantityPriceEntity> pqp = new ArrayList<ProductQuantityPriceEntity>();
       pqp.add(currentPQP);
       pqp.add(currentPQP2);
       pqp.add(currentPQP3);
       pqp.add(currentPQP4);
       current.setProductQuantityPrice(pqp);
       current.modified(getLoginPerson());
       getFacade().edit(current);
       return"View";
    }

    public String prepareReview() {
        current = (PurchaseOrderEntity) getItems().getRowData();
        resetContactAndAddresses();
        return "Review";
    }

    public String update() {
        try {
            ArrayList<ProductQuantityPriceEntity> pqp = new ArrayList<ProductQuantityPriceEntity>(current.getProductQuantityPrice());
            ArrayList<RoleEntity> role = new ArrayList<RoleEntity>(getCurrentUser().getRoles());
            boolean manager = false;
            for (int i = 0; i < role.size(); i++) {
                if (role.get(i).getRoleName().equals("Sales Manager")) {
                    manager = true;
                    break;
                }
            }
            for (int i = 0; i < pqp.size(); i++) {
                if (pqp.get(i).getQuantity() != 0) {
                    if (manager) {
                        if ((getPrice(pqp.get(i), current).get(0) * 0.8) > pqp.get(i).getPricePerUnit()) {
                            throw new Exception("Your account only permits discounts up to 20%.");
                        }

                    } else if ((getPrice(pqp.get(i), current).get(0) * 0.9) > pqp.get(i).getPricePerUnit()) {
                        throw new Exception("Your account only permits discounts up to 10%.");
                    }
                }
            }
            
            //verify that shipping requests match pqp
            String verificationResult = verifyShippingRequestTotal();
            if(!verificationResult.isEmpty()){
                JsfUtil.addErrorMessage(verificationResult);
                return null;
            }

            current.modified(getLoginPerson());
            getFacade().edit(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("PurchaseOrderEntityUpdated"));
            return "View";
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        current = (PurchaseOrderEntity) getItems().getRowData();
        performDestroy();
        recreateModel();
        return "List";
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        return "List";
    }

    private void performDestroy() {
        try {
            current.modified(getLoginPerson());
            getFacade().remove(current);
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/Bundle").getString("PurchaseOrderEntityDeleted"));
        } catch (Exception e) {
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
        }
    }

    public DataModel getItems() {
        if (items == null) {
            if (getLoginPerson() instanceof SystemUserEntity) {
                items = getFacade().getAllPurchaseOrder();
            } else if (getLoginPerson() instanceof CustomerEntity) {
                items = getFacade().getAllPurchaseOrderForCustomer(getLoginPerson().getId());
            }
        }
        return items;
    }

    private void recreateModel() {
        items = null;
        shippingAddresses = new ArrayList<AddressEntity>();
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    public String getAttribute() {
        return attribute;
    }

    public void setAttribute(String attribute) {
        this.attribute = attribute;
    }

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public void setSearchItems(DataModel searchItems) {
        this.searchItems = searchItems;
    }

    public CustomerEntityController getCustomerEntityController() {
        return customerEntityController;
    }

    public void setCustomerEntityController(CustomerEntityController customerEntityController) {
        this.customerEntityController = customerEntityController;
    }

    public SalesLeadEntityController getSalesLeadEntityController() {
        return salesLeadEntityController;
    }

    public void setSalesLeadEntityController(SalesLeadEntityController salesLeadEntityController) {
        this.salesLeadEntityController = salesLeadEntityController;
    }

    public SalesQuotationEntity getSelectedItem() {
        return selectedItem;
    }

    public void setSelectedItem(SalesQuotationEntity selectedItem) {
        this.selectedItem = selectedItem;
    }

    public SalesQuotationEntityController getSalesQuotationEntityController() {
        return salesQuotationEntityController;
    }

    public void setSalesQuotationEntityController(SalesQuotationEntityController salesQuotationEntityController) {
        this.salesQuotationEntityController = salesQuotationEntityController;
    }

    public SystemUserEntity getSalesExecutive() {
        return salesExecutive;
    }

    public void setSalesExecutive(SystemUserEntity salesExecutive) {
        this.salesExecutive = salesExecutive;
    }

    public SalesOrderEntityController getSalesOrderEntityController() {
        return salesOrderEntityController;
    }

    public void setSalesOrderEntityController(SalesOrderEntityController salesOrderEntityController) {
        this.salesOrderEntityController = salesOrderEntityController;
        this.salesOrderEntityController.setPurchaseOrderEntityController(this);
    }

    public SystemMessageController getSystemMessageController() {
        return systemMessageController;
    }

    public void setSystemMessageController(SystemMessageController systemMessageController) {
        this.systemMessageController = systemMessageController;
    }

    public ProductQuantityPriceEntity getCurrentPQP() {
        return currentPQP;
    }

    public void setCurrentPQP(ProductQuantityPriceEntity currentPQP) {
        this.currentPQP = currentPQP;
    }

    public ProductQuantityPriceEntity getCurrentPQP2() {
        return currentPQP2;
    }

    public void setCurrentPQP2(ProductQuantityPriceEntity currentPQP2) {
        this.currentPQP2 = currentPQP2;
    }

    public ProductQuantityPriceEntity getCurrentPQP3() {
        return currentPQP3;
    }

    public void setCurrentPQP3(ProductQuantityPriceEntity currentPQP3) {
        this.currentPQP3 = currentPQP3;
    }

    public ProductQuantityPriceEntity getCurrentPQP4() {
        return currentPQP4;
    }

    public void setCurrentPQP4(ProductQuantityPriceEntity currentPQP4) {
        this.currentPQP4 = currentPQP4;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @FacesConverter(forClass = PurchaseOrderEntity.class)
    public static class PurchaseOrderEntityControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            PurchaseOrderEntityController controller = (PurchaseOrderEntityController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "purchaseOrderEntityController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuffer sb = new StringBuffer();
            sb.append(value);
            return sb.toString();
        }

        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof PurchaseOrderEntity) {
                PurchaseOrderEntity o = (PurchaseOrderEntity) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + PurchaseOrderEntityController.class.getName());
            }
        }
    }

    public ProductQuantityPriceEntity getSelectedPQP() {
        if (getCurrentPQP() == null) {
            setCurrentPQP(new ProductQuantityPriceEntity());
        }
        return getCurrentPQP();
    }

    public ProductQuantityPriceEntity getSelectedPQP2() {
        if (getCurrentPQP2() == null) {
            setCurrentPQP2(new ProductQuantityPriceEntity());
        }
        return getCurrentPQP2();
    }

    public ProductQuantityPriceEntity getSelectedPQP3() {
        if (getCurrentPQP3() == null) {
            setCurrentPQP3(new ProductQuantityPriceEntity());
        }
        return getCurrentPQP3();
    }

    public ProductQuantityPriceEntity getSelectedPQP4() {
        if (getCurrentPQP4() == null) {
            setCurrentPQP4(new ProductQuantityPriceEntity());
        }
        return getCurrentPQP4();
    }

    public PaymentMethod[] getPaymentMethod() {
        return PaymentMethod.values();
    }

    public String quotationSelect(SelectEvent event) {
        current.setSalesQuotation(selectedItem);
        return "Create?faces-redirect=true";
    }

    public Date getToday() {
        Date today = new Date();
        return today;
    }

    public String prepareCreateSO() {
        salesOrderEntityController.prepareCreate();
        salesOrderEntityController.getSelected().setPurchaseOrder(current);
        salesOrderEntityController.getSelected().setCustomer(current.getCustomer());
        salesOrderEntityController.getSelected().setTotalPrice(current.getTotalPrice());
        salesOrderEntityController.getSelected().setSystemUser(current.getCustomer().getCustomerExecutive());
        current.setSalesOrder(salesOrderEntityController.getSelected());
        return "/entities/salesOrderEntity/Create?faces-redirect=true";
    }

    public boolean createSOLink() {
        System.out.println(current.getCustomer());
        if (!current.getCustomer().isBlackListed() && current.getSalesOrder() == null && checkSystemUser()) {
            return true;
        } else {
            return false;
        }
    }

    public String viewPOFromSO() {
        current = getSalesOrderEntityController().getSelected().getPurchaseOrder();
        resetContactAndAddresses();
        //selectedItemIndex = pagination.getPageFirstItem() + getItems().getRowIndex();
        return "/entities/purchaseOrderEntity/View";
    }

    public ContactEntityController getContactEntityController() {
        return contactEntityController;
    }

    public void setContactEntityController(ContactEntityController contactEntityController) {
        this.contactEntityController = contactEntityController;
    }

    public List<AddressEntity> getShippingAddresses() {
        return shippingAddresses;
    }

    public void setShippingAddresses(List<AddressEntity> shippingAddresses) {
        this.shippingAddresses = shippingAddresses;
    }

    public PurchaseOrderEntity getCurrent() {
        return current;
    }

    public void setCurrent(PurchaseOrderEntity current) {
        this.current = current;
    }

    public void saveNote() {
        Date now = getToday();
        SimpleDateFormat sdfDate = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");
        current.getServiceRequests().add(getCurrentUser().getName() + " (" + sdfDate.format(now) + "): " + note);
        //getFacade().edit(current);
        note = "";
    }

    public void saveAndPost(ActionEvent event) throws Exception {
        current.setSystemUser(getCurrentUser());
        //send email to customer
        Mailer.doSend("staff.merlion@gmail.com",
                current.getCustomer().getContact().getEmail(),
                "", "Purchase Order #" + current.getId() + "Reviewed", "Dear " + current.getCustomer().getTitle() + " " + current.getCustomer().getFullname() + ", your purchase order has been reviewed.",
                null, null);

    }

    public void updatePricePerUnitTotalPrice(PurchaseOrderEntity purchaseOrder, ProductQuantityPriceEntity pqp, double pricePerUnit) {
        double totalPrice = 0;
        pqp.setPrice(pricePerUnit * pqp.getQuantity());
        ArrayList<ProductQuantityPriceEntity> allPqp = new ArrayList<ProductQuantityPriceEntity>(purchaseOrder.getProductQuantityPrice());
        for (int i = 0; i < allPqp.size(); i++) {
            totalPrice = totalPrice + allPqp.get(i).getPrice();
        }
    }
    
    public void setDate(Date date) {
        current.setPreferredLeadTime(date);
    }
}
